package com.qingcloud.adminbackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qingcloud.adminbackend.command.ComponentInstanceContainer;
import com.qingcloud.adminbackend.command.SourceCommandLoader;
import com.qingcloud.adminbackend.constant.DictConstant;
import com.qingcloud.adminbackend.entity.config.SysDictionaryConfig;
import com.qingcloud.adminbackend.entity.equipment.EquipmentCommandRecord;
import com.qingcloud.adminbackend.entity.product.*;
import com.qingcloud.adminbackend.entity.sensor.SysSensorFactorConfigDTO;
import com.qingcloud.adminbackend.enums.BizExceptionEnum;
import com.qingcloud.adminbackend.exception.WmCommonException;
import com.qingcloud.adminbackend.mapper.*;
import com.qingcloud.adminbackend.pojo.IdListParam;
import com.qingcloud.adminbackend.pojo.dto.sysproduct.PageProductListDTO;
import com.qingcloud.adminbackend.pojo.dto.sysproduct.SysProductAddDTO;
import com.qingcloud.adminbackend.pojo.dto.sysproduct.SysProductModDTO;
import com.qingcloud.adminbackend.pojo.dto.sysproduct.SysProductSourceVO;
import com.qingcloud.adminbackend.pojo.product.CommandResultDTO;
import com.qingcloud.adminbackend.pojo.product.ComponentParam;
import com.qingcloud.adminbackend.pojo.product.ProductCommandFieldDTO;
import com.qingcloud.adminbackend.pojo.product.SendCommandResult;
import com.qingcloud.adminbackend.pojo.vo.sysproduct.PageProductListVO;
import com.qingcloud.adminbackend.pojo.vo.sysproduct.ProductDetailVO;
import com.qingcloud.adminbackend.pojo.vo.sysproduct.ProductListVO;
import com.qingcloud.adminbackend.pojo.vo.sysproduct.SysProductCommandVO;
import com.qingcloud.adminbackend.provider.fusion.DataFusionApiHelper;
import com.qingcloud.adminbackend.service.ISysDictionaryConfigService;
import com.qingcloud.adminbackend.service.ISysProductTypeService;
import com.qingcloud.adminbackend.service.ISysSensorFactorConfigService;
import com.qingcloud.adminbackend.utils.DataUtil;
import com.qingcloud.base.api.remote.eqcenter.EqcenterApi;
import com.qingcloud.base.context.UserContextHolder;
import com.qingcloud.base.pojo.ApiResult;
import com.qingcloud.base.pojo.PageResult;
import com.qingcloud.base.remote.eqcentor.CommandInfo;
import com.qingcloud.base.remote.pojo.LoginUserDTO;
import com.qingcloud.df.sdk.exchange.model.ProtocolFieldModel;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 蛙鸣产品型号定义 服务实现类
 * </p>
 *
 * @author luozehua
 * @since 2019-04-12
 */
@Service
public class SysProductTypeServiceImpl extends ServiceImpl<SysProductTypeMapper, SysProductType> implements ISysProductTypeService {

    private static Logger log = LoggerFactory.getLogger(SysProductTypeServiceImpl.class);
    @Resource
    private ISysDictionaryConfigService iSysDictionaryConfigService;

    @Resource
    private SysProductTypeMapper sysProductTypeMapper;

    @Resource
    private SysProductDecoderMapper decoderMapper;

    @Resource
    private SysProductCommandMapper sysProductCommandMapper;

    @Resource
    private ISysSensorFactorConfigService iSysSensorFactorConfigService;

    @Resource
    private SysProductClassifyCommandMapper sysProductClassifyCommandMapper;


    @Resource
    private SysProductCommandClassifyMapper sysProductCommandClassifyMapper;

    @Resource
    private SysProductTopicMapper sysProductTopicMapper;

    @Resource
    private DataFusionApiHelper dataFusionApiHelper;

    @Resource
    private SysProductCommandSourceMapper commandSourceMapper;

    @Resource
    private SysProductCommandFieldMapper commandFieldMapper;

    @Resource
    private EquipmentCommandRecordMapper commandRecordMapper;

    @Resource
    private EqcenterApi eqcenterApi;

    @Value("${qingcloud.common.workspaceRoot}")
    private String workspace;
    @Value("${qingcloud.common.ideVolumeWorkspace}")
    private String volumeWorkspace;
    /**
     * 指令源码基础目录
     */
    private String cmdSourceBase = "source"+File.separator+"command";
    /**
     * 指令示例项目
     */
    private String exampleCommandProject = "%s"+File.separator+"template"+File.separator+"command-template";
    private String commandScriptPackage = "com.qingcloud.iot.command";
    private String templateCommandClassName  = "COMMANDCLASSNAME";

//    String defaultJavaPath =  sourceDir + File.separator+"src"+File.separator+"main"+File.separator+"java"+File.separator+ packagePath+File.separator+fileName+".java";
    String defaultJavaPath =  "%s" + File.separator+"src"+File.separator+"main"+File.separator+"java"+File.separator+ "%s"+File.separator+"%s"+".java";
    /**
     * 新增产品
     *
     * @param sysProductAddDTO 新增产品请求DTO
     * @param currentUserId    当前用户id
     * @return 产品id
     */
    @Override
    public Long addProduct(SysProductAddDTO sysProductAddDTO, String currentUserId) {
        //产品型号
        String productType = sysProductAddDTO.getProductType();
        LambdaQueryWrapper<SysProductType> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SysProductType::getProductType, productType);
        Long selectCount = sysProductTypeMapper.selectCount(wrapper);
        if (selectCount > 0) {
            throw new WmCommonException(BizExceptionEnum.PARA_ERROR, "产品型号已经存在");
        }

        SysProductType sysProductType = new SysProductType();
        BeanUtil.copyProperties(sysProductAddDTO, sysProductType);
        LocalDateTime now = LocalDateTime.now();
        sysProductType.setCreateDt(now);
        sysProductType.setModifyDt(now);
        sysProductType.setCreateBy(currentUserId);
        sysProductType.setModifyBy(currentUserId);
        sysProductTypeMapper.insert(sysProductType);
        return sysProductType.getId();
    }

    /**
     * 修改产品
     *
     * @param sysProductModDTO 修改产品请求DTO
     * @param currentUserId    当前用户id
     * @return 产品id
     */
    @Override
    public Long modProduct(SysProductModDTO sysProductModDTO, String currentUserId) {
        //产品型号
        String productType = sysProductModDTO.getProductType();
        LambdaQueryWrapper<SysProductType> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SysProductType::getProductType, productType);
        SysProductType baseProduct = sysProductTypeMapper.selectOne(wrapper);
        //判断产品型号是否重复
        if (baseProduct != null && !baseProduct.getId().equals(sysProductModDTO.getId())) {
            throw new WmCommonException(BizExceptionEnum.PARA_ERROR, "产品型号已经存在");
        }
        SysProductType sysProductType = new SysProductType();
        BeanUtil.copyProperties(sysProductModDTO, sysProductType);
        LocalDateTime now = LocalDateTime.now();
        sysProductType.setModifyDt(now);
        sysProductType.setModifyBy(currentUserId);
        int updateCout = sysProductTypeMapper.updateById(sysProductType);
        if (updateCout < 0) {
            throw new WmCommonException(BizExceptionEnum.PARA_ERROR, "产品不存在");
        }
        return sysProductType.getId();
    }

    /**
     * 删除产品
     *
     * @param productTypeIdList 产品id列表
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteProductList(List<Integer> productTypeIdList) {
        if (CollectionUtil.isEmpty(productTypeIdList)) {
            throw new WmCommonException(BizExceptionEnum.PARA_ERROR, "产品id列表不能为空");
        }
        //检查产品id是否关联设备
        for (Integer productTypeId : productTypeIdList) {
            SysProductType sysProductType = sysProductTypeMapper.selectById(productTypeId);
            if (sysProductType != null) {
                Integer refDeviceCount = sysProductTypeMapper.countProductRefDeivce(sysProductType.getProductType());
                if (refDeviceCount > 0) {
                    throw new WmCommonException(BizExceptionEnum.PARA_ERROR, "产品id存在设备关联不能删除,产品id:" + productTypeId);
                }
            }
        }
        //删除解码器
        deleteDecoder(productTypeIdList);

        //删除指令
        deleteProductCommand(productTypeIdList);

        //删除产品主题表
        deleteTopic(productTypeIdList);
        //删除产品表
        int deleteCount = sysProductTypeMapper.deleteBatchIds(productTypeIdList);
        log.info("删除条数:{}", deleteCount);

    }

    /**
     * 删除产品主题
     *
     * @param productTypeIdList 产品型号id集合
     */
    private void deleteTopic(List<Integer> productTypeIdList) {
        LambdaQueryWrapper<SysProductTopic> deleteWrapper = Wrappers.lambdaQuery();
        deleteWrapper.in(SysProductTopic::getProductTypeId, productTypeIdList);
        int delete = sysProductTopicMapper.delete(deleteWrapper);
        log.info("删除产品主题表(sys_product_topic)成功，删除条数:{}", delete);
    }

    /**
     * 删除产品指令
     * 删除以下表:
     * 产品分类表:sys_product_command_classify
     * 产品指令表:sys_product_command
     * 产品分类与产品指令关系表:sys_product_classify_command_r
     *
     * @param productTypeIdList 产品型号id集合
     * @return 源码id
     */
    private List<Integer> deleteProductCommand(List<Integer> productTypeIdList) {
        LambdaQueryWrapper<SysProductCommandClassify> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.in(SysProductCommandClassify::getProductTypeId, productTypeIdList);
        //查询产品分类
        List<SysProductCommandClassify> classifyList = sysProductCommandClassifyMapper.selectList(queryWrapper);
        List<Integer> sourceIdList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(classifyList)) {
            List<Integer> classifyIdList = classifyList.stream().map(SysProductCommandClassify::getId).collect(Collectors.toList());
            //删除分类表
            int deleteCount = sysProductCommandClassifyMapper.deleteBatchIds(classifyIdList);
            log.info("删除产品分类表(sys_product_command_classify)成功，删除条数:{}", deleteCount);
            //查询指令表
            LambdaQueryWrapper<SysProductCommand> queryCommandWrapper = Wrappers.lambdaQuery();
            queryCommandWrapper.in(SysProductCommand::getProductTypeId, productTypeIdList);
            //通过产品型号id查询产品指令集合
            List<SysProductCommand> sysProductCommands = sysProductCommandMapper.selectList(queryCommandWrapper);
            //得到指令id集合
            List<Integer> commandIdList = sysProductCommands.stream().map(SysProductCommand::getId).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(sysProductCommands)) {
                //删除指令表
                deleteCount = sysProductCommandMapper.deleteBatchIds(commandIdList);
                log.info("删除指令表(sys_product_command)成功，删除条数:{}", deleteCount);
                sourceIdList = sysProductCommands.stream().map(SysProductCommand::getSourceId).collect(Collectors.toList());

                //删除指令分类和指令关系表
                LambdaQueryWrapper<SysProductClassifyCommand> deleteWrapper = Wrappers.lambdaQuery();
                deleteWrapper.in(SysProductClassifyCommand::getProductCommandClassifyId, classifyIdList);
                deleteCount = sysProductClassifyCommandMapper.delete(deleteWrapper);
                log.info("删除指令分类和指令关系表(sys_product_classify_command_r)成功，删除条数:{}", deleteCount);
            }
        }
        //返回源码id
        return sourceIdList;
    }

    /**
     * 删除解码器
     *
     * @param productTypeIdList 产品型号id集合
     * @return 源码id集合
     */
    private void deleteDecoder(List<Integer> productTypeIdList) {
        //查询产品解码器源码表
        LambdaQueryWrapper<SysProductDecoder> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.in(SysProductDecoder::getProductId, productTypeIdList);
        decoderMapper.delete(queryWrapper);
    }

    /**
     * 分页产品列表
     *
     * @param pageProductListDTO 请求DTO
     * @return 分页返回数据
     */
    @Override
    public Page<PageProductListVO> pageProductList(PageProductListDTO pageProductListDTO) {
        int pageNum = pageProductListDTO.getPageNumber() == null ? 1 : pageProductListDTO.getPageNumber();
        int pageSize = pageProductListDTO.getPageSize() == null ? 10 : pageProductListDTO.getPageSize();
        Page<PageProductListVO> page = new Page<>(pageNum, pageSize);
        sysProductTypeMapper.pageProductList(page, pageProductListDTO);
        buildPageProductListVO(page);
        return page;
    }

    /**
     * 构建返回 产品列表返回
     *
     * @param page 分页数据
     */
    private void buildPageProductListVO(Page<PageProductListVO> page) {
        List<PageProductListVO> records = page.getRecords();

        if (CollectionUtil.isNotEmpty(records)) {
            Map<String, SysDictionaryConfig> productSeriesMap = iSysDictionaryConfigService.getDictMapByType(DictConstant.PRODUCT_SERIES);
            Map<String, SysDictionaryConfig> productMap = iSysDictionaryConfigService.getDictMapByType(DictConstant.PRODUCT);
            Map<String, SysDictionaryConfig> protocolTypeMap = iSysDictionaryConfigService.getDictMapByType(DictConstant.PROTOCOL_TYPE);
            Map<String, SysDictionaryConfig> equipmentStatesMap = iSysDictionaryConfigService.getDictMapByType(DictConstant.EQUIPMENT_STATES);
            Map<String, SysDictionaryConfig> runningModulsMap = iSysDictionaryConfigService.getDictMapByType(DictConstant.RUNNING_MODULS);

            //查询监测因子
            List<SysSensorFactorConfigDTO> sensorFactorList = iSysSensorFactorConfigService.getSensorFactor();
            Map<Integer, SysSensorFactorConfigDTO> sensorFactorMap = sensorFactorList.stream().collect(Collectors.toMap(SysSensorFactorConfigDTO::getFactorId, a -> a, (k1, k2) -> k1));

            for (PageProductListVO vo : records) {
                //产品系列
                Integer productSeries = vo.getProductSeries();
                String dictStr = DataUtil.getDictByStr(productSeriesMap, productSeries.toString());
                vo.setProductSeries_d(dictStr);
                //产品
                Integer product = vo.getProduct();
                dictStr = DataUtil.getDictByStr(productMap, product.toString());
                vo.setProduct_d(dictStr);
                //产品协议
                Integer protocolCoe = vo.getProtocolCoe();
                dictStr = DataUtil.getDictByStr(protocolTypeMap, protocolCoe.toString());
                vo.setProtocolCoe_d(dictStr);
                //监测因子
                String sensorFactors = vo.getSensorFactors();
                String sensorFactorStr = DataUtil.getSensorFactorStr(sensorFactorMap, sensorFactors);
                vo.setSensorFactors_d(sensorFactorStr);
                //设备状态
                String equipmentStates = vo.getEquipmentStates();
                dictStr = DataUtil.getDictByStr(equipmentStatesMap, equipmentStates);
                vo.setEquipmentStates_d(dictStr);
                //可用运行模式
                String runningModuls = vo.getRunningModuls();
                dictStr = DataUtil.getDictByStr(runningModulsMap, runningModuls);
                vo.setRunningModuls_d(dictStr);
            }
        }
    }


    /**
     * 产品详情查询
     *
     * @param productTypeId 产品id
     * @return 产品详情
     */
    @Override
    public ProductDetailVO productDetail(Integer productTypeId) {
        ProductDetailVO productDetailVO = new ProductDetailVO();
        SysProductType sysProductType = sysProductTypeMapper.selectById(productTypeId);
        if (sysProductType == null) {
            throw new WmCommonException(BizExceptionEnum.DATA_NULL, "产品不存在");
        }
        BeanUtil.copyProperties(sysProductType, productDetailVO);
        //查询产品关联设备数量
        Integer refDeviceCount = sysProductTypeMapper.countProductRefDeivce(productDetailVO.getProductType());
        productDetailVO.setRefDeviceCount(refDeviceCount);

        buildProductDetailVO(productDetailVO);
        return productDetailVO;
    }

    /**
     * 构建产品详情VO
     *
     * @param vo 产品详情VO
     */
    private void buildProductDetailVO(ProductDetailVO vo) {

        //产品系列
        Integer productSeries = vo.getProductSeries();
        if (productSeries != null) {
            SysDictionaryConfig dictConfig = iSysDictionaryConfigService.getDictByTypeAndCode(DictConstant.PRODUCT_SERIES, productSeries + "");
            if (dictConfig != null) {
                vo.setProductSeries_d(dictConfig.getName());
            } else {
                vo.setProductSeries_d(productSeries + "");
            }
        }
        //产品
        Integer product = vo.getProduct();
        if (product != null) {
            SysDictionaryConfig dictConfig = iSysDictionaryConfigService.getDictByTypeAndCode(DictConstant.PRODUCT, product + "");
            if (dictConfig != null) {
                vo.setProduct_d(dictConfig.getName());
            } else {
                vo.setProduct_d(product + "");
            }

        }

        //产品协议
        Integer protocolCoe = vo.getProtocolCoe();
        if (protocolCoe != null) {
            SysDictionaryConfig dictConfig = iSysDictionaryConfigService.getDictByTypeAndCode(DictConstant.PROTOCOL_TYPE, protocolCoe + "");
            if (dictConfig != null) {
                vo.setProtocolCoe_d(dictConfig.getName());
            } else {
                vo.setProtocolCoe_d(protocolCoe + "");
            }
        }
        //监测因子
        String sensorFactors = vo.getSensorFactors();
        if (StrUtil.isNotBlank(sensorFactors)) {
            //查询监测因子
            List<SysSensorFactorConfigDTO> sensorFactorList = iSysSensorFactorConfigService.getSensorFactor();
            Map<Integer, SysSensorFactorConfigDTO> sensorFactorMap = sensorFactorList.stream().collect(Collectors.toMap(SysSensorFactorConfigDTO::getFactorId, a -> a, (k1, k2) -> k1));
            vo.setSensorFactors_d(DataUtil.getSensorFactorStr(sensorFactorMap, sensorFactors));
        }

        //设备状态
        String equipmentStates = vo.getEquipmentStates();
        if (StrUtil.isNotBlank(equipmentStates)) {
            vo.setEquipmentStates_d(iSysDictionaryConfigService.getDictStr(DictConstant.EQUIPMENT_STATES, equipmentStates));
        }
        //可用运行模式
        String runningModuls = vo.getRunningModuls();
        if (StrUtil.isNotBlank(runningModuls)) {
            vo.setRunningModuls_d(iSysDictionaryConfigService.getDictStr(DictConstant.RUNNING_MODULS, runningModuls));
        }
    }

    /**
     * 查询解码器组件信息
     */
    @Override
    public PageResult<SysProductDecoder> pageComponentDecoders(ComponentParam componentParam) {
        String json = dataFusionApiHelper.pageComponentDecoders(componentParam.getName(),
                componentParam.getPage(), componentParam.getPageSize());
        if (StrUtil.isNotBlank(json)) {
            final PageResult<SysProductDecoder> pageResult = JSONObject.parseObject(json, new TypeReference<PageResult<SysProductDecoder>>() {
            });
            for (SysProductDecoder it : pageResult.getData()) {
                it.setId(null);
            }
            return pageResult;
        }
        return new PageResult<>();
    }

    /**
     * 保存或者修改产品解码器
     *
     * @return 产品id
     */
    @Override
    public Integer addOrModProductDecoder(List<SysProductDecoder> decoders) {
        int successSize = 0;
        for (SysProductDecoder decoder : decoders) {
            LambdaQueryWrapper<SysProductDecoder> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(SysProductDecoder::getComponentId, decoder.getComponentId())
                    .eq(SysProductDecoder::getProductId, decoder.getProductId());
            //查询产品源码信息
            Long size = decoderMapper.selectCount(wrapper);
            //已经绑定
            if (size > 0) {
                continue;
            }
            decoderMapper.insert(decoder);
            ++successSize;
        }
        return successSize;
    }

    @Override
    public PageResult<SysProductDecoder> productDecoderPage(ComponentParam componentParam) {
        int pageNum = componentParam.getPage();
        int pageSize = componentParam.getPageSize();
        Page<SysProductDecoder> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<SysProductDecoder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SysProductDecoder::getProductId, componentParam.getProductId());
        if (StrUtil.isNotBlank(componentParam.getName())) {
            wrapper.and(tempWrapper -> tempWrapper.like(SysProductDecoder::getName, componentParam.getName()).or()
                    .like(SysProductDecoder::getSoftwareName, componentParam.getName()));
        }
        final IPage<SysProductDecoder> resultPage = decoderMapper.selectPage(page, wrapper);
        final PageResult<SysProductDecoder> decoderPageResult = new PageResult<>();
        decoderPageResult.setCode(0);
        decoderPageResult.setCount(resultPage.getTotal());
        decoderPageResult.setData(resultPage.getRecords());
        return decoderPageResult;
    }

    @Override
    public int deleteDecoder(IdListParam param) {
        return decoderMapper.deleteBatchIds(param.getIds());
    }

    /**
     * 查询产品解码器
     *
     * @param productId 产品id
     * @return 产品源码信息
     */
    @Override
    public SysProductSourceVO productDecoderInfo(Integer productId) {
        SysProductSourceVO sysProductSourceVO = new SysProductSourceVO();
        LambdaQueryWrapper<SysProductDecoder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SysProductDecoder::getProductId, productId);
        SysProductDecoder sysProductDecoder = decoderMapper.selectOne(wrapper);
        if (sysProductDecoder == null) {
            return sysProductSourceVO;
        }
        List<Integer> sourceIdList = new ArrayList<>();
        //通过源码id列表查询源码信息
        ApiResult apiResult = dataFusionApiHelper.findSourcesBySourceId(sourceIdList);
        //检查结果
        ApiResult.checkResult(apiResult);

        sysProductSourceVO.setProductId(sysProductDecoder.getProductId());
        sysProductSourceVO.setName(sysProductDecoder.getName());

        JSONArray jsonArray = JSONArray.parseArray(JSONObject.toJSONString(apiResult.getResult()));

        if (CollectionUtil.isNotEmpty(jsonArray)) {
            JSONObject jsonObject = (JSONObject) jsonArray.get(0);
            sysProductSourceVO.setSource((String) jsonObject.get("source"));
        }
        return sysProductSourceVO;
    }

    /**
     * 保存或者修改产品指令
     *
     * @param dto           请求DTO
     * @param currentUserId 当前用户
     * @return 指令id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysProductCommand saveOrModProductCommand(SysProductCommandDto dto, String currentUserId) {
        //插入或者更新产品指令数据
        SysProductCommand updateCommand = new SysProductCommand();

        //指令源码信息保存
        SysProductCommandSource commandSource = getSourceId(dto);
        updateCommand.setSourceId(commandSource.getId());

        //保存指令
        Integer productCommandId = insertOrUpdateProductCommand(dto, currentUserId, updateCommand);

        //更新产品对应的产品分类
        updateProductClassify(productCommandId, currentUserId, dto);
        //返回指令信息
        updateCommand.setSourceDir(commandSource.getSourceDir());
        return updateCommand;
    }

    /**
     * 得到源码id
     *
     * @param dto 请求DTO
     * @return 源码id
     */
    private SysProductCommandSource getSourceId(SysProductCommandDto dto) {
        if (null != dto.getId()) {//更新数据
            SysProductCommand sysProductCommand = sysProductCommandMapper.selectById(dto.getId());
            if (null == sysProductCommand) {
                throw new WmCommonException(BizExceptionEnum.DATA_NULL, "产品指令信息不存在");
            }
            return commandSourceMapper.selectById(sysProductCommand.getSourceId());
        }

        //保存指令源码
        SysProductCommandSource commandSource = new SysProductCommandSource();
        commandSource.setLanguageType(1);
        commandSource.setFileType(1);
        commandSource.setState(0);
        commandSourceMapper.insert(commandSource);
        String sourceFileName =  dto.getCommandModule() + "_" + commandSource.getId();
        String sourceDir = cmdSourceBase + File.separator + sourceFileName;
        commandSource.setSourceDir(sourceDir);//保存相对路径
        //如果源码目录不存在，创建目录，并复制示例项目
        String sourceDir0 = workspace+File.separator+sourceDir;
        if (!FileUtil.exist(sourceDir0)) {
            copyExampleCommand(sourceDir0,sourceFileName);
        }
        commandSourceMapper.updateById(commandSource);
        return commandSource;
    }

    /**
     * 复制样例代码
     * @param sourceDir
     */
    private void copyExampleCommand(String sourceDir,String fileName){
        try {

            FileUtil.mkParentDirs(sourceDir);
            String fileRootPath = getRootPath();
            String path= String.format(exampleCommandProject,fileRootPath);
            File file  = new File(path);
            log.debug("source origin path: "+ path);
            log.debug("source target path: "+ sourceDir);

            if(file!=null && file.exists()) {
                FileUtil.copyContent(new File(path), new File(sourceDir), true);
            }
            replaceHolder(sourceDir,fileName);
        } catch (Exception e) {
            //ignore
            e.printStackTrace();
            System.out.println("copy simple error： "+e.getMessage());
        }
    }

    private void replaceHolder(String sourceDir, String fileName){

        String packagePath =  javaCommandPackage2Path();
        String defaultPath =  String.format(defaultJavaPath,sourceDir,packagePath,templateCommandClassName);
        String javaPath =  String.format(defaultJavaPath,sourceDir,packagePath,fileName);
        try {
            // 读取原始文件
            Path file = Paths.get(defaultPath);
            List<String> lines = Files.readAllLines(file);
            // 替换字符串
            for (int i = 0; i < lines.size(); i++) {
                lines.set(i, lines.get(i).replace(templateCommandClassName, fileName));
            }
            // 写回文件
            File javaFile  = new File(javaPath);
            Path newFile  = javaFile.toPath();
            Files.write(newFile, lines);
            FileUtil.del(file);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private String javaCommandPackage2Path(){
        String  newStr = commandScriptPackage.replaceAll("\\.","/");
        return newStr;
    }

    /**
     * 插入或者更新产品指令数据
     *
     * @param dto           请求DTO
     * @param currentUserId 当前用户
     * @param updateCommand 需要更新的实体
     * @return 指令id
     */
    private Integer insertOrUpdateProductCommand(SysProductCommandDto dto, String currentUserId, SysProductCommand updateCommand) {
        BeanUtil.copyProperties(dto, updateCommand);
        Integer productCommandId;
        LocalDateTime now = LocalDateTime.now();
        if (null != dto.getId()) {//更新数据
            productCommandId = dto.getId();
            updateCommand.setModifyDt(now);
            updateCommand.setModifyBy(currentUserId);
            sysProductCommandMapper.updateById(updateCommand);
        } else {//插入数据
            updateCommand.setCreateDt(now);
            updateCommand.setModifyDt(now);
            updateCommand.setCreateBy(currentUserId);
            updateCommand.setModifyBy(currentUserId);
            sysProductCommandMapper.insert(updateCommand);
            productCommandId = updateCommand.getId();
        }
        return productCommandId;
    }

    /**
     * 更新产品对应的产品分类
     * sys_product_classify_command_r
     *
     * @param productCommandId 产品指令id
     * @param currentUserId    当前用户
     * @param dto              请求DTO
     */
    private void updateProductClassify(Integer productCommandId, String currentUserId, SysProductCommandDto dto) {
        LambdaQueryWrapper<SysProductClassifyCommand> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SysProductClassifyCommand::getProductCommandId, productCommandId);
        //通过产品指令id查询产品指令分类与产品指令关系表sys_product_classify_command_r
        SysProductClassifyCommand productClassify = sysProductClassifyCommandMapper.selectOne(wrapper);
        if (productClassify == null) {
            SysProductClassifyCommand sysProductClassifyCommand = new SysProductClassifyCommand();
            sysProductClassifyCommand.setProductCommandId(productCommandId);
            sysProductClassifyCommand.setProductCommandClassifyId(dto.getProductCommandClassifyId());
            LocalDateTime now = LocalDateTime.now();
            sysProductClassifyCommand.setCreateDt(now);
            sysProductClassifyCommand.setModifyDt(now);
            sysProductClassifyCommand.setCreateBy(currentUserId);
            sysProductClassifyCommand.setModifyBy(currentUserId);
            //插入产品指令分类与产品指令关系表(sys_product_classify_command_r)
            sysProductClassifyCommandMapper.insert(sysProductClassifyCommand);
        } else {
            productClassify.setProductCommandId(productCommandId);
            productClassify.setProductCommandClassifyId(dto.getProductCommandClassifyId());
            LocalDateTime now = LocalDateTime.now();
            productClassify.setModifyDt(now);
            productClassify.setModifyBy(currentUserId);
            //更新产品指令分类与产品指令关系表(sys_product_classify_command_r)
            sysProductClassifyCommandMapper.updateById(productClassify);
        }
    }

    /**
     * 删除产品指令
     *
     * @param productCommandId 产品指令id
     * @return 影响条数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteProductCommand(Integer productCommandId) {
        SysProductCommand sysProductCommand = sysProductCommandMapper.selectById(productCommandId);

        LambdaQueryWrapper<SysProductClassifyCommand> deleteWrapper = Wrappers.lambdaQuery();
        deleteWrapper.eq(SysProductClassifyCommand::getProductCommandId, productCommandId);
        //删除产品指令分类和指令关系
        int deleteCount = sysProductClassifyCommandMapper.delete(deleteWrapper);
        log.info("删除产品指令分类和指令关系(sys_product_classify_command_r)成功，删除条数:{}", deleteCount);
        deleteCount = sysProductCommandMapper.deleteById(productCommandId);
        log.info("删除产品指令表(sys_product_command)成功，删除条数:{}", deleteCount);
        if (sysProductCommand != null) {
            Integer sourceId = sysProductCommand.getSourceId();
            if (sourceId != null) {
                //删除指令源码
                commandSourceMapper.deleteById(sourceId);
                //删除指令字段
                LambdaQueryWrapper<SysProductCommandField> deleteFieldWrapper = Wrappers.lambdaQuery();
                commandFieldMapper.delete(deleteFieldWrapper.eq(SysProductCommandField::getCommandId, productCommandId));
            }
        }
        return deleteCount;

    }

    /**
     * 查询产品指令信息
     *
     * @param productCommandId 产品指令id
     * @return 产品信息
     */
    @Override
    public SysProductCommandVO queryCommandInfo(Integer productCommandId) {

        SysProductCommandVO resultVo = sysProductCommandMapper.selectCommandInfo(productCommandId);
        if (resultVo != null) {
            Integer sourceId = resultVo.getSourceId();
            final SysProductCommandSource commandSource = commandSourceMapper.selectById(sourceId);
            if (Objects.nonNull(commandSource)) {
                String absPath = workspace+ File.separator+ commandSource.getSourceDir();
                String fileName  =  resultVo.getCommandModule()+"_"+sourceId;
                //如果源码目录不存在，首先创建目录，并复制示例项目
                if (!FileUtil.exist(absPath) && !FileUtil.exist(absPath+File.separator+"pom.xml") ) {
                    copyExampleCommand(absPath,fileName);
                } else {
                    updateCommandFile(commandSource,fileName);
                }
                //IDE磁盘映射对应的目录
                String ideWorkspace = volumeWorkspace+ File.separator+ commandSource.getSourceDir();
                resultVo.setSourceDir(absPath);
            }
        }
        return resultVo;
    }

    private void updateCommandFile(SysProductCommandSource commandSource, String fileName){
        String source  = commandSource.getSource();
        String pom  = commandSource.getPom();
        String doc  = commandSource.getDoc();
        String absPath = workspace+ File.separator+ commandSource.getSourceDir();
        String sourcePath=String.format(defaultJavaPath,absPath,javaCommandPackage2Path(),fileName);
        String pomPath = absPath+File.separator+"pom.xml";
        String docPath = absPath+File.separator+"readme.md";
        FileUtil.writeUtf8String(source,sourcePath);
        FileUtil.writeUtf8String(pom,pomPath);
        FileUtil.writeUtf8String(doc,docPath);
    }

    private void readCommandFile(SysProductCommandSource commandSource, String fileName){
        String absPath = workspace+ File.separator+ commandSource.getSourceDir();
        String sourcePath=String.format(defaultJavaPath,absPath,javaCommandPackage2Path(),fileName);
        String pomPath = absPath+File.separator+"pom.xml";
        String docPath = absPath+File.separator+"readme.md";

        String source  = FileUtil.readUtf8String(sourcePath);
        String pom  = FileUtil.readUtf8String(pomPath);
        String doc  = FileUtil.readUtf8String(docPath);
        commandSource.setSource(source);
        commandSource.setPom(pom);
        commandSource.setDoc(doc);
    }

    /**
     * 保存指令源码信息
     *
     * @param commandId 指令ID
     * @return
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public String saveCommandSource(Integer commandId) {
        final SysProductCommand sysProductCommand = sysProductCommandMapper.selectById(commandId);
        final SysProductCommandSource commandSource = commandSourceMapper.selectById(sysProductCommand.getSourceId());
        String sourceDir = commandSource.getSourceDir();
        String sourceFileName = sysProductCommand.getCommandModule()+"_"+commandSource.getId();
        //首先找到java源码文件
//        final List<File> fileList = FileUtil.loopFiles(sourceDir);
//        File javaFile = null;
//        for (File file : fileList) {
//            if (file.getAbsolutePath().contains("main") && file.getName().endsWith("java")) {
//                javaFile = file;
//                break;
//            }
//        }
//        if (Objects.isNull(javaFile)) {
//            throw new WmCommonException("指令项目没有找到java源码文件");
//        }
//        //解析java源文件
//        String javaSource = FileUtil.readUtf8String(javaFile);
//        if (StrUtil.isBlank(javaSource)) {
//            throw new WmCommonException(javaFile.getName() + "文件是空的");
//        }
//        //解析pom文件
//        String pom = "";
//        for (File file : fileList) {
//            if ("pom.xml".equalsIgnoreCase(file.getName())) {
//                pom = FileUtil.readUtf8String(file);
//                break;
//            }
//        }
//        //解析文档内容
//        String doc = "";
//        for (File file : fileList) {
//            if ("readme.md".equalsIgnoreCase(file.getName())) {
//                doc = FileUtil.readUtf8String(file);
//                break;
//            }
//        }
        readCommandFile(commandSource,sourceFileName);
        //移除旧的实例对象
        ComponentInstanceContainer.removeInstance(commandSource.getId());
        //加载源码文件
        final SourceCommandLoader sourceCommandLoader = new SourceCommandLoader(commandSource.getId(), sysProductCommand.getCommandModule(), commandSource.getSource(), commandSource.getPom());
        //删除原来的字段
        //删除指令字段
        LambdaQueryWrapper<SysProductCommandField> deleteFieldWrapper = Wrappers.lambdaQuery();
        commandFieldMapper.delete(deleteFieldWrapper.eq(SysProductCommandField::getCommandId, commandId));
        //解析字段
        final List<ProtocolFieldModel> fieldList = sourceCommandLoader.parseField();
        if (CollUtil.isNotEmpty(fieldList)) {
            final List<SysProductCommandField> tempList = fieldList.stream().map(it -> {
                final SysProductCommandField field = new SysProductCommandField();
                field.setCommandId(commandId);
                BeanUtils.copyProperties(it, field);
                return field;
            }).collect(Collectors.toList());
            commandFieldMapper.batchInsert(tempList);
        }
        //保存源码信息
        commandSourceMapper.updateById(commandSource);
        sysProductCommand.setTransforType(sourceCommandLoader.getContentType());
        sysProductCommandMapper.updateById(sysProductCommand);
        return "保存成功";
    }

    /**
     * 查询指令字段信息
     */
    @Override
    public ProductCommandFieldDTO findCommandField(Integer commandId) {
        //指令信息
        final SysProductCommand sysProductCommand = sysProductCommandMapper.selectById(commandId);
        //指令字段信息
        LambdaQueryWrapper<SysProductCommandField> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysProductCommandField::getCommandId, commandId);
        wrapper.orderByAsc(SysProductCommandField::getFieldIndex);
        final List<SysProductCommandField> fieldList = commandFieldMapper.selectList(wrapper);
        //按照输入类型分组
        final Map<String, List<SysProductCommandField>> fieldObj = fieldList.stream().collect(Collectors.groupingBy(it -> it.getValueFrom().toString(),
                TreeMap::new, Collectors.toList()));
        ProductCommandFieldDTO productCommandFieldDTO = new ProductCommandFieldDTO();
        BeanUtils.copyProperties(sysProductCommand, productCommandFieldDTO);
        productCommandFieldDTO.setFieldObj(fieldObj);
        return productCommandFieldDTO;
    }

    /**
     * 获取指令内容
     */
    @Override
    public String getCommandContent(JSONObject jsonObject) {
        //设备编号
        String equipmentId = jsonObject.getString("equipmentId");
        if (StrUtil.isBlank(equipmentId)) {
            throw new WmCommonException("设备编号参数equipmentId不能为空");
        }
        //查询指令信息
        SysProductCommand productCommand = sysProductCommandMapper.selectById(jsonObject.getIntValue("commandId"));
        //查询指令源码
        SysProductCommandSource commandSource = commandSourceMapper.selectById(productCommand.getSourceId());
        SourceCommandLoader sourceCommandLoader = new SourceCommandLoader(commandSource.getId(),
                productCommand.getCommandModule(), commandSource.getSource(), commandSource.getPom());
        for (String key : jsonObject.keySet()) {
            if (!"commandId".equalsIgnoreCase(key) && !"equipmentId".equalsIgnoreCase(key)) {
                sourceCommandLoader.setCommandFieldValue(key, jsonObject.getString(key));
            }
        }
        return sourceCommandLoader.getContent();
    }

    /**
     * 发送指令
     */
    @Override
    public CommandResultDTO sendCommand(JSONObject jsonObject) {
        //设备编号
        String equipmentId = jsonObject.getString("equipmentId");
        if (StrUtil.isBlank(equipmentId)) {
            throw new WmCommonException("设备编号参数equipmentId不能为空");
        }
        //查询指令信息
        SysProductCommand productCommand = sysProductCommandMapper.selectById(jsonObject.getIntValue("commandId"));
        //查询指令源码
        SysProductCommandSource commandSource = commandSourceMapper.selectById(productCommand.getSourceId());
        SourceCommandLoader sourceCommandLoader = new SourceCommandLoader(commandSource.getId(),
                productCommand.getCommandModule(), commandSource.getSource(), commandSource.getPom());
        for (String key : jsonObject.keySet()) {
            if (!"commandId".equalsIgnoreCase(key) && !"equipmentId".equalsIgnoreCase(key)) {
                sourceCommandLoader.setCommandFieldValue(key, jsonObject.getString(key));
            }
        }
        //指令序列号
        String sn = sourceCommandLoader.getSerialNumber();
        //指令发送编码
        String format = sourceCommandLoader.getFormat();
        //指令发送内容
        final String content = sourceCommandLoader.getContent();
        //保存指令记录
        saveCommandRecord(equipmentId, sn, format, content);
        //下发指令
        final CommandInfo commandInfo = new CommandInfo();
        commandInfo.setSerialNumber(sn);
        commandInfo.setFormat(format);
        commandInfo.setContent(content);
        commandInfo.setObjectId(equipmentId);
        commandInfo.setWaitResponse(productCommand.getWaitResponse());
        final ApiResult apiResult = eqcenterApi.sendCommand(commandInfo);
        if (apiResult.isSuccessful()) {
            final SendCommandResult commandResult = JSONObject.parseObject(JSONObject.toJSONString(apiResult.getResult()), SendCommandResult.class);
            final CommandResultDTO dto = new CommandResultDTO();
            dto.setCommandResult(commandResult.getResult());
            dto.setParseResult(commandResult.getParseResult());
            return dto;
        }
        final CommandResultDTO dto = new CommandResultDTO();
        dto.setCommandResult(CollUtil.newArrayList("调用指令接口失败", apiResult.getError()));
        return dto;
    }

    private void saveCommandRecord(String equipmentId, String sn, String format, String content) {
        final EquipmentCommandRecord record = new EquipmentCommandRecord();
        record.setSn(sn);
        record.setFormat(format);
        record.setContent(content);
        record.setCreateDt(LocalDateTime.now());
        record.setEquipmentId(equipmentId);
        record.setState(0);
        final LoginUserDTO userInfo = UserContextHolder.getUserInfo();
        if (userInfo != null) {
            record.setCreateBy(userInfo.getUserId());
        }
        commandRecordMapper.insert(record);
    }

    @Override
    public List<ProductListVO> selectAllProductList() {
        return sysProductTypeMapper.productList();
    }

    /**
     * 获取类的全名称
     *
     * @param sourceCode 源码
     * @return 类的全名称
     */
    public static String getPackageClass(String sourceCode) {
        String className = null;
        //包名
        String regex = "(?im)^\\s*package\\s+([^;]+);";
        Matcher packageName = Pattern.compile(regex).matcher(sourceCode);
        //类名
        String regex1 = "(?m)^\\s*public\\s+class\\s+(\\w+)\\b";
        Matcher classNameMatcher = Pattern.compile(regex1).matcher(sourceCode);
        if (packageName.find() && classNameMatcher.find()) {
            className = packageName.group(1).trim() + "." + classNameMatcher.group(1).trim();
        }
        log.info("className：" + className);
        if (StrUtil.isBlank(className)) {
            throw new WmCommonException(BizExceptionEnum.PARA_ERROR, "获取源码全类名异常！");
        }
        return className;
    }

    private static String getRootPath() {
        String jarPath = jarPath  = System.getProperty("user.dir");
        log.debug("jarPath:" + jarPath);
        return jarPath;
    }
}
